【JavaScript】スコープ - 変数の有効範囲
JavaScriptのスコープについて解説します。
検証環境
スコープ
スコープは“変数の有効範囲”です。
JavaScriptのスコープはグローバルスコープとローカルスコープに分類され、ローカルスコープは更にブロックスコープと関数スコープに分かれます。
グローバルスコープ
グローバルスコープは“プログラムのどこからでもアクセスが可能です。”
トップレベルで宣言した変数はこのスコープを持ちます。
___ih_hl_start
let scope = "global scope";
___ih_hl_end
console.log(scope);
function check() {
console.log(scope);
}
check();
global scope
global scope
また、varキーワードで宣言したグローバルスコープの変数はWindowオブジェクトのプロパティに追加されます。
※ Windowオブジェクトはブラウザ実行のJavaScriptにおいて、最上位のオブジェクトです。
___ih_hl_start
var scope_v = "var global scope";
let scope_l = "let global scope";
const scope_c = "const global scope";
___ih_hl_end
console.log(window.scope_v);
console.log(window.scope_l);
console.log(window.scope_c);
var global scope
undefined
undefined
なお、上記サンプルから分かるようにlet
キーワード、const
キーワードで宣言した変数はWindowオブジェクトに追加されません。
ローカルスコープ
ローカルスコープはブロックスコープと関数スコープに分かれます。
ブロックスコープ
ブロックスコープはブロック({}
)単位のスコープです。
ブロック内で宣言した変数がこのスコープを持ちます。
if( true ) {
___ih_hl_start
let scope = 'block scope';
___ih_hl_end
console.log(scope);
}
console.log(scope);
block scope
Uncaught ReferenceError: scope is not defined
このようにブロック外からアクセスするとエラーが発生します。
ただし、var
キーワードの宣言変数はアクセスが可能になります。
if( true ) {
___ih_hl_start
var scope = 'block scope';
___ih_hl_end
console.log(scope);
}
console.log(scope);
block scope
block scope
関数スコープ
関数スコープは関数単位のスコープです。
関数で宣言した変数や仮引数がこのスコープを持ちます。
___ih_hl_start
function check( scope_a ) {
___ih_hl_end
___ih_hl_start
let scope_v = 'function scope( variable )';
___ih_hl_end
console.log(scope_a);
console.log(scope_v);
}
check('function scope( argument )');
console.log(scope_a);
console.log(scope_v);
function scope( argument )
function scope( variable )
Uncaught ReferenceError: scope_a is not defined
このように関数外からアクセスするとエラーが発生します。
※ 11行目のconsole.log(scope_a)
でエラーが発生しプログラムが停止していますが、console.log(scope_v)
も同様のエラーになります。
任意ブロック
任意のブロックを作成し、スコープ化することができます。
{
___ih_hl_start
let scope = 'block scope';
___ih_hl_end
console.log(scope);
}
console.log(scope);
block scope
Uncaught ReferenceError: scope is not defined
ネスト
ブロックはネスト(階層化)できます。
ネストでは下層から上層の変数にアクセスできますが、その逆はできません。
{
let scope_o = 'scope outer';
{
let scope_i = 'scope inner';
___ih_hl_start
console.log(scope_o);
___ih_hl_end
}
___ih_hl_start
console.log(scope_i);
___ih_hl_end
}
scope outer
Uncaught ReferenceError: scope_i is not defined
5行目のアクセス(下層から上層)は成功していますが、7行目のアクセス(上層から下層)はエラーが発生しています。
また、スコープが異なれば同名の変数を宣言できます。
{
let scope = 'scope outer';
{
___ih_hl_start
let scope = 'scope inner';
___ih_hl_end
console.log(scope);
}
console.log(scope);
}
scope inner
scope outer
異なる変数として扱われるため、変数の操作(値の更新など)が影響することはありません。
ただし、var
宣言変数は影響するので注意が必要です。
{
var scope = 'scope outer';
{
___ih_hl_start
var scope = 'scope inner';
___ih_hl_end
console.log(scope);
}
console.log(scope);
}
scope inner
scope inner